feat: add endpoint to retrieve Mermaid diagram of SQL connection database structure#1750
Conversation
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughIntroduces a new "Get Connection Diagram" feature enabling SQL database connections to generate Mermaid ER diagrams and descriptions from their schema metadata. The implementation includes a new controller endpoint, use case, utilities for diagram generation, data structures, DTOs, and comprehensive E2E tests. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Controller
participant UseCase
participant DB
participant Diagram as Diagram Builder
Client->>Controller: GET /connection/diagram/:connectionId
Controller->>Controller: Validate connectionId & extract masterPwd, userId
Controller->>UseCase: execute(GetConnectionDiagramDs)
UseCase->>DB: Decrypt & load connection by ID
UseCase->>UseCase: Validate SQL connection type
UseCase->>DB: Resolve userEmail for agent-based connections
UseCase->>DB: Validate schema cache & retrieve tables
UseCase->>DB: Fetch table metadata (structure, PKs, FKs)
UseCase->>Diagram: buildMermaidErDiagram(databaseName, tables)
Diagram->>Diagram: Generate ER diagram with relationships
Diagram-->>UseCase: Return diagram + description
UseCase-->>Controller: Return ConnectionDiagramResponseDTO
Controller-->>Client: HTTP 200 with diagram & metadata
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 60 minutes.Comment |
There was a problem hiding this comment.
Pull request overview
This PR introduces a new authenticated backend endpoint to generate and return a Mermaid erDiagram representation (plus a textual summary) of a SQL connection’s database schema, along with end-to-end coverage for the new behavior.
Changes:
- Added
GET /connection/diagram/:connectionIdcontroller route, DI wiring, and a new use case to build the diagram from DB metadata. - Introduced utilities to detect SQL connection types and to render Mermaid ER diagrams + descriptions.
- Added non-SaaS AVA E2E tests for the new endpoint (success, unsupported DB type, unauthenticated).
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| backend/test/ava-tests/non-saas-tests/non-saas-connection-diagram-e2e.test.ts | Adds E2E coverage for the new connection diagram endpoint. |
| backend/src/exceptions/text/messages.ts | Adds a new message for rejecting non-SQL connection diagram requests; minor formatting adjustment. |
| backend/src/entities/connection/utils/is-sql-connection-type.util.ts | Adds helper to classify which connection types are treated as SQL for diagram support. |
| backend/src/entities/connection/utils/build-mermaid-er-diagram.util.ts | Implements Mermaid erDiagram + description string builder from table metadata. |
| backend/src/entities/connection/use-cases/use-cases.interfaces.ts | Adds IGetConnectionDiagram interface. |
| backend/src/entities/connection/use-cases/get-connection-diagram.use.case.ts | Implements schema introspection and diagram generation use case. |
| backend/src/entities/connection/connection.module.ts | Wires the new use case and routes; adds middleware route entry. |
| backend/src/entities/connection/connection.controller.ts | Exposes GET /connection/diagram/:connectionId endpoint with guards/swagger metadata. |
| backend/src/entities/connection/application/dto/connection-diagram-response.dto.ts | Adds response DTO for diagram payload. |
| backend/src/entities/connection/application/data-structures/get-connection-diagram.ds.ts | Adds input DS for the new use case. |
| backend/src/common/data-injection.tokens.ts | Adds DI token GET_CONNECTION_DIAGRAM. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const connection = await this._dbContext.connectionRepository.findAndDecryptConnection(connectionId, masterPwd); | ||
| if (!connection) { | ||
| throw new HttpException({ message: Messages.CONNECTION_NOT_FOUND }, HttpStatus.BAD_REQUEST); | ||
| } | ||
| if (!isSqlConnectionType(connection.type)) { | ||
| throw new BadRequestException(Messages.DIAGRAM_NOT_SUPPORTED_FOR_CONNECTION_TYPE); | ||
| } |
There was a problem hiding this comment.
findAndDecryptConnection() can throw Messages.MASTER_PASSWORD_MISSING / Messages.MASTER_PASSWORD_INCORRECT (see custom-connection-repository-extension.ts), but this use case doesn't catch/translate those errors. That will surface as a 500 for a client-side error when the master password header is missing/incorrect. Catch these specific errors and rethrow an HttpException with HttpStatus.BAD_REQUEST (and the same type values used elsewhere, e.g. no_master_key / invalid_master_key).
| const realTables = tables.filter((t) => !t.isView); | ||
| const tableInputs: Array<MermaidTableInput> = await Promise.all( | ||
| realTables.map((t) => this.collectTableInfo(dao, t.tableName, userEmail)), | ||
| ); |
There was a problem hiding this comment.
Promise.all(realTables.map(...)) will kick off 3 queries per table concurrently (structure/PK/FK). On connections with many tables this can overwhelm the DB / exceed pool limits and cause avoidable timeouts. Consider adding a concurrency limit / batching (e.g. process tables in chunks) so the endpoint remains reliable for larger schemas.
| private async safe<T>(fn: () => Promise<T>, fallback: T): Promise<T> { | ||
| try { | ||
| return await fn(); | ||
| } catch { | ||
| return fallback; | ||
| } |
There was a problem hiding this comment.
The safe() helper swallows all errors and returns a fallback without logging or surfacing partial-failure information. This can lead to silently incomplete diagrams and makes production failures hard to diagnose. At minimum, log (or capture to Sentry) the table name + operation when a DAO call fails, or propagate an error so the client can see the failure reason.
| t.is(typeof body.diagram, 'string'); | ||
| t.is(typeof body.description, 'string'); | ||
| t.is(typeof body.generatedAt, 'string'); | ||
| t.notThrows(() => new Date(body.generatedAt)); |
There was a problem hiding this comment.
t.notThrows(() => new Date(body.generatedAt)) doesn't actually validate the timestamp because new Date(...) never throws (it returns an Invalid Date object on bad input). Use an assertion that checks parsability instead (e.g. !Number.isNaN(Date.parse(body.generatedAt)) or new Date(...).getTime() is finite).
| t.notThrows(() => new Date(body.generatedAt)); | |
| t.false(Number.isNaN(Date.parse(body.generatedAt))); |
Summary by CodeRabbit
New Features
Tests